class SegmentTreeForBivalent:
    """二值线段树：区域查询和更新最大值"""

    class _Node:
        """线段树结点"""
        __slots__ = "start", "end", "val", "left", "right"

        def __init__(self, start, end):
            self.start = start  # 左侧边界（包含）
            self.end = end  # 右侧边界（包含）
            self.left = None  # 结点左子结点
            self.right = None  # 结点右子节点
            self.val = False  # 当前结点最小值

    def __init__(self, size):
        """初始化线段树实例"""
        self.root = self._Node(0, size)

    def _update(self, node, pos1, pos2, data):
        """更新数据"""
        # 当前区间正好为当前结点的情况：即不需要继续分裂的情况
        if node.start == pos1 and node.end == pos2:
            node.val = data
            node.left, node.right = None, None

        # 当前区间为当前结点的部分的情况：即需要继续分裂的情况
        else:
            mid = (node.start + node.end) // 2

            # 创建两个子结点
            if node.left is None:
                node.left = self._Node(node.start, mid)
                node.left.val = node.val
            if node.right is None:
                node.right = self._Node(mid + 1, node.end)
                node.right.val = node.val

            # 更新当前结点的子结点
            if pos2 <= mid:
                self._update(node.left, pos1, pos2, data)
            elif pos1 >= mid + 1:
                self._update(node.right, pos1, pos2, data)
            else:
                self._update(node.left, pos1, mid, data)
                self._update(node.right, mid + 1, pos2, data)

            # 更新当前结点的值
            node.val = node.left.val and node.right.val

    def _query(self, node, start, end):
        """查询数据"""

        # 当前区间正好为当前结点的情况：即不需要继续分裂的情况
        if node.start == start and node.end == end:
            return node.val

        # 当前结点没有子结点的情况：即当前结点下所有位置的结果一致的情况
        elif node.left is None and node.right is None:
            return node.val

        # 当前区间为当前结点的部分的情况：即需要继续分裂的情况
        else:
            mid = (node.start + node.end) // 2

            # 查询当前结果的最小值
            if end <= mid:
                return self._query(node.left, start, end)
            elif start >= mid + 1:
                return self._query(node.right, start, end)
            else:
                return self._query(node.left, start, mid) and self._query(node.right, mid + 1, end)

    def query_one(self, query):
        return self._query(self.root, query, query)

    def query_range(self, start, end):
        return self._query(self.root, start, end)

    def update_one(self, query, data):
        self._update(self.root, query, query, data)

    def update_range(self, start, end, data):
        self._update(self.root, start, end, data)


class RangeModule:

    def __init__(self):
        self.tree = SegmentTreeForBivalent(10 ** 9)

    def addRange(self, left: int, right: int) -> None:
        self.tree.update_range(left, right - 1, True)

    def queryRange(self, left: int, right: int) -> bool:
        return self.tree.query_range(left, right - 1)

    def removeRange(self, left: int, right: int) -> None:
        self.tree.update_range(left, right - 1, False)


if __name__ == "__main__":
    obj = RangeModule()
    obj.addRange(10, 20)
    obj.removeRange(14, 16)
    print(obj.queryRange(10, 14))  # True
    print(obj.queryRange(13, 15))  # False
    print(obj.queryRange(16, 17))  # True
